package de.schollit.seomonitor.p2;

import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.equinox.internal.p2.ui.sdk.ProvSDKUIActivator;
import org.eclipse.equinox.internal.provisional.p2.core.ProvisionException;
import org.eclipse.equinox.internal.provisional.p2.ui.ProvUI;
import org.eclipse.equinox.internal.provisional.p2.ui.QueryableMetadataRepositoryManager;
import org.eclipse.equinox.internal.provisional.p2.ui.policy.Policy;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.statushandlers.StatusManager;

/**
 * PreloadingRepositoryHandler provides background loading of
 * repositories before executing the provisioning handler.
 * 
 * @since 3.5
 */
@SuppressWarnings("restriction")
abstract class PreloadingRepositoryHandler extends AbstractHandler {

	Object LOAD_FAMILY = new Object();

	/**
	 * The constructor.
	 */
	public PreloadingRepositoryHandler() {
		// constructor
	}

	/**
	 * Execute the command.
	 */
	public Object execute(ExecutionEvent event) {
		try {
			final String profileId = ProvSDKUIActivator.getSelfProfileId();
			BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
				public void run() {
					doExecuteAndLoad(profileId, preloadRepositories());
				}
			});

		} catch (ProvisionException e) {
			MessageDialog.openInformation(null, Messages.Handler_SDKUpdateUIMessageTitle, Messages.Handler_CannotLaunchUI);
			ProvUI.handleException(e, null, StatusManager.LOG);
		}
		return null;
	}

	void doExecuteAndLoad(final String profileId, boolean preloadRepositories) {
		//cancel any load that is already running
		Job.getJobManager().cancel(LOAD_FAMILY);
		final QueryableMetadataRepositoryManager queryableManager = new QueryableMetadataRepositoryManager(Policy.getDefault().getQueryContext(), false);
		if (preloadRepositories) {
			Job loadJob = new Job(Messages.InstallNewSoftwareHandler_LoadRepositoryJobLabel) {

				protected IStatus run(IProgressMonitor monitor) {
					queryableManager.loadAll(monitor);
					return Status.OK_STATUS;
				}

				public boolean belongsTo(Object family) {
					return family == LOAD_FAMILY;
				}

			};
			setLoadJobProperties(loadJob);
			if (waitForPreload()) {
				loadJob.addJobChangeListener(new JobChangeAdapter() {
					public void done(IJobChangeEvent event) {
						if (PlatformUI.isWorkbenchRunning())
							if (event.getResult().isOK()) {
								PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
									public void run() {
										doExecute(profileId, queryableManager);
									}
								});
							}
					}
				});
				loadJob.setUser(true);
				loadJob.schedule();

			} else {
				loadJob.setSystem(true);
				loadJob.setUser(false);
				loadJob.schedule();
				doExecute(profileId, queryableManager);
			}
		} else {
			doExecute(profileId, queryableManager);
		}
	}

	protected abstract void doExecute(String profileId, QueryableMetadataRepositoryManager manager);

	protected boolean preloadRepositories() {
		return true;
	}

	protected boolean waitForPreload() {
		return true;
	}

	protected void setLoadJobProperties(Job loadJob) {
		// nothing to do by default
	}

	/**
	 * Return a shell appropriate for parenting dialogs of this handler.
	 * @return a Shell
	 */
	protected Shell getShell() {
		return ProvUI.getDefaultParentShell();
	}
}
